# module name node.py
# $Id: node.py ddcad87fab9c 2013/08/17 19:20:30 pgurumur $
# Copyright (c) 2013 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# File node.py generated on Mon, July 29, 2013 16:33:00 PM
#
from __future__ import division
__version__  = "$Revision: ddcad87fab9c $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2013-08-17 19:20:30Z $"


class InvalidOperand(object):
   def __init__(self, *args):
      self._args = args

   def __call__(self, function):
      def wrapper(*args, **kwargs):
         if isinstance(args[1], self._args):
            raise exception.InternalError("Invalid type of operand")

         return function(*args, **kwargs)
      return wrapper

class BerylNode(object):
   def __init__(self, Value, Type = None):
      self._nodetype = None

      try:
         if issubclass(Type, (int, BerylInteger)):
            self._value = int(Value)
         elif issubclass(Type, (str, BerylString)):
            self._value = str(Value)
         elif issubclass(Type, (float, BerylFloat)):
            self._value = float(Value)
         else:
            raise ValueError("unknown type %s" %str(Type))
      except ValueError as err:
         print(type(Type))
         raise ValueError("need to follow it up more!")
      else:
         self._nodetype = Type

   def __repr__(self):
      return str(self)

   value = property(fget = lambda self: self._value)

class BerylFloat(BerylNode):
   def __init__(self, Value = 0.0):
      super(BerylFloat, self).__init__(Value, float)

   def __str__(self):
      retval = None
      if self._value:
         retval = "%0.05f" %self.value

      return retval

   def __int__(self):
      retval = 0
      if self._value:
         retval = int(self.value)

      return retval

   def __float__(self):
      return self.value

   def __iadd__(self, Value):
      print(type(self._value), type(Value))
      self._value += Value
      return self

   def __imul__(self, Value):
      self._value *= Value

class BerylInteger(BerylNode):
   pass

class BerylString(BerylNode):
   pass

class BerylVariable(object):
   def __init__(self, Value, Name = None):
      self._value = None
      self._name = None
      self._type = None

      if isinstance(Value, (int, long)):
         self._value = Value
      elif isinstance(Value, str):
         self._value = Value
      elif isinstance(Value, float):
         self._value = Value
      elif isinstance(Value, BerylVariable):
         self._value = Value.value
      else:
         raise ValueError("unknown type %s" %type(Value))

      temp = None
      try:
         if isinstance(self._value, str):
            temp = int(self._value)
      except ValueError:
         pass

      if temp:
         self._value = temp

      if Name:
         if isinstance(Name, str):
            self._name = Name
         else:
            raise ValueError("name must be a string")
      else:
         self._name = ""

      if self._value:
         self._type = type(self._value)

   def __int__(self):
      retval = None
      if isinstance(self._value, (int, long)):
         retval = self.value
      elif isinstance(self._value, float):
         retval = int(self.value)

      return retval

   def __float__(self):
      retval = None
      if isinstance(self._value, (int, long)):
         retval = float(self.value)
      elif isinstance(self._value, float):
         retval = self.value

      return retval

   def __hash__(self):
      return hash(self.value)

   def __str__(self):
      retval = None
      if self._name:
         retval = self._name
      else:
         retval = str(self.value)

      return retval

   def __add__(self, value):
      return BerylVariable(value + self)

   def __sub__(self, value):
      return BerylVariable(value - self)

   def __mul__(self, value):
      return BerylVariable(value * self)

   def __truediv__(self, value):
      return BerylVariable(value / self)

   def __radd__(self, value):
      temp = None
      if isinstance(value, type(self.value)):
         temp = self._value + value
      elif issubclass(value, BerylVariable):
         temp = self._value + value.value
      else:
         raise ValueError("unknown type for value: %s" %type(value))

      return BerylVariable(temp)

   def __iadd__(self, value):
      if isinstance(value, type(self.value)):
         self._value += value
      elif isinstance(value, BerylVariable):
         self._value += value.value

      return self

   def __rsub__(self, value):
      temp = None
      if isinstance(value, type(self.value)):
         temp = self._value - value
      elif isinstance(value, BerylVariable):
         temp = self._value - value.value
      else:
         raise ValueError("unknown type for value: %s" %type(value))

      return BerylVariable(temp)

   def __isub__(self, value):
      if isinstance(value, type(self.value)):
         self._value -= value
      elif isinstance(value, BerylVariable):
         self._value -= value.value

      return self

   def __rmul__(self, value):
      temp = None
      if isinstance(value, type(self.value)):
         temp = self._value * value
      elif isinstance(value, BerylVariable):
         temp = self._value * value.value
      else:
         raise ValueError("unknown type for value: %s" %type(value))

      return BerylVariable(temp)

   def __imul__(self, value):
      if isinstance(value, type(self.value)):
         self._value *= value
      elif isinstance(value, BerylVariable):
         self._value *= value.value

      return self

   def __rtruediv__(self, value):
      temp = None
      if isinstance(value, type(self.value)):
         temp = self._value / value
      elif isinstance(value, BerylVariable):
         temp = self._value / value.value

      return BerylVariable(temp)

   def __itruediv__(self, value):
      if isinstance(value, type(self.value)):
         self._value /= value
      elif isinstance(value, BerylVariable):
         self._value /= value.value

      return self

   def __getslice__(self, sidx = 0, eidx = None):
      retval = None
      if isinstance(self.value, str):
         retval = self.value[sidx:eidx]

      return retval

   def get_name(self):
      return self._name

   def set_name(self, value):
      if isinstance(value, str):
         self._name = value
      else:
         raise ValueError("variable name has to be string")

   name = property(get_name, set_name)
   value = property(fget = lambda self: self._value)
